package com.demo.app.config.log;

import com.alibaba.fastjson.JSON;
import com.demo.app.config.exception.RepetitionSubmitException;
import com.demo.app.mapper.log.LogMapper;
import enums.TokenEnum;
import model.entity.sys.SysLog;
import model.dto.sys.user.UserDto;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import util.IpUtil;
import com.demo.app.config.jwt.JwtTokenUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/**
 * @program: fire_control
 * @description: 切点配置
 * @author: fbl
 * @create: 2021-02-04 16:10
 **/
@Aspect
@Component
public class SysAspect {

    @Autowired
    LogMapper logMapper;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    RedisTemplate<Object, Object> redisTemplate;

    private static final String LOGIN_URL = "/login";

    /**
     * @Author fbl
     * @Description 定义切点 @Pointcut 在注解的位置切入代码
     * @Date 16:31 2021/2/4
     * @Param
     */
    @Pointcut("@annotation(com.demo.app.config.log.MyInterceptor)")
    public void logPointCut() {
    }

    /**
     * @Author fbl
     * @Description 切面 配置通知
     * @Date 16:31 2021/2/4
     * @Param
     */
    @AfterReturning("logPointCut()")
    @Transactional(rollbackFor = Exception.class)
    public void saveSysLog(JoinPoint joinPoint) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        SysLog sysLog = new SysLog();
        // 获取ip
        String ipAddr = IpUtil.getIpAddr(request);
        sysLog.setIp(ipAddr);
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取操作
        MyInterceptor MyInterceptor = method.getAnnotation(MyInterceptor.class);
        sysLog.setOperation(MyInterceptor.value());
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethod(className + "." + methodName);

        //请求的参数
        Object[] args = joinPoint.getArgs();
        if (request.getRequestURL().toString().contains(LOGIN_URL)) {
            //将参数所在的数组转换成json
            String loginParStr = JSON.toJSONString(args[0]);
            UserDto userDto = JSON.parseObject(loginParStr, UserDto.class);
            userDto.setPassword("***");
            sysLog.setParams(JSON.toJSONString(userDto));
            sysLog.setUserName(userDto.getUserName());
            logMapper.insert(sysLog);
        } else {
            // 得到用户token
            String token = getToken(request);
            String userName =  JwtTokenUtils.getUsername(token);
            String param = JSON.toJSONString(args);
            sysLog.setUserName(userName);
            sysLog.setParams(param);
            logMapper.insert(sysLog);
        }
    }

    /**
     * 拦截重复请求
     * @param joinPoint
     * @throws ServletException
     * @throws IOException
     */
    //@Before("logPointCut()")
    public void repetitionSubmit(JoinPoint joinPoint) throws ServletException, IOException {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) requestAttributes).getResponse();
        //请求的参数
        Object[] args = joinPoint.getArgs();

        if (!request.getRequestURL().toString().contains(LOGIN_URL)) {
            String token = getToken(request);
            // 得到用户url
            String requestURI = request.getRequestURI();
            String repetitionToken = token + requestURI;
            Object o = redisTemplate.opsForValue().get(repetitionToken);
            if (Objects.nonNull(o) && Objects.nonNull(args)) {
                if (redisTemplate.opsForValue().get(repetitionToken).equals(args[0])) {
                    request.setAttribute("repetitionSubmitException", new RepetitionSubmitException());
                    request.getRequestDispatcher("/repetitionSubmitException").forward(request, response);
                }
            }else{
                redisTemplate.opsForValue().set(repetitionToken, args[0], 10, TimeUnit.SECONDS);
            }
        }
    }

    private String getToken(HttpServletRequest request) {
        // 得到用户token
        String tokenHeader = request.getHeader(TokenEnum.TOKEN_HEADER.getValue());
        return tokenHeader.replace(TokenEnum.TOKEN_PREFIX.getValue(), "");
    }
}
